﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Kyozy.MiniblinkNet
{
    public struct JsValue
    {
        private static Dictionary<string, wkeJsNativeFunction> sm_jsFunctionDictionary = new Dictionary<string, wkeJsNativeFunction>();
        public Int64 Value;

        public JsValue(Int64 value)
        {
            this.Value = value;
        }
        /// <summary>
        /// 重载隐式转换
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static implicit operator Int64(JsValue v)
        {
            return v.Value;
        }
        /// <summary>
        /// 重载隐式转换
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public static implicit operator JsValue(Int64 v)
        {
            return new JsValue(v);
        }
        /// <summary>
        /// 获取值类型
        /// </summary>
        /// <returns></returns>
        public jsType GetType()
        {
            return MBApi.jsTypeOf(Value);
        }
        /// <summary>
        /// 转换到Int32
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public int ToInt32(IntPtr jsExecState)
        {
            return MBApi.jsToInt(jsExecState, Value);
        }
        /// <summary>
        /// 转换到float
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public float ToFloat(IntPtr jsExecState)
        {
            return MBApi.jsToFloat(jsExecState, Value);
        }
        /// <summary>
        /// 转换到double
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public double ToDouble(IntPtr jsExecState)
        {
            return MBApi.jsToDouble(jsExecState, Value);
        }
        /// <summary>
        /// 转换到bool
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public bool ToBoolean(IntPtr jsExecState)
        {
            return MBApi.jsToBoolean(jsExecState, Value) != 0;
        }
        /// <summary>
        /// 转换到string
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public string ToString(IntPtr jsExecState)
        {
            IntPtr pStr = MBApi.jsToTempStringW(jsExecState, Value);
            if (pStr == IntPtr.Zero)
            {
                return null;
            }
            return Marshal.PtrToStringUni(pStr);
        }

        public JsValue Get(IntPtr jsExecState, string propName)
        {
            return MBApi.jsGet(jsExecState, this.Value, propName);
        }
        public void Set(IntPtr jsExecState, string propName, JsValue v)
        {
            MBApi.jsSet(jsExecState, this.Value, propName, v.Value);
        }
        public JsValue GetAt(IntPtr jsExecState, int index)
        {
            return MBApi.jsGetAt(jsExecState, this.Value, index);
        }
        public void SetAt(IntPtr jsExecState, int index, JsValue v)
        {
            MBApi.jsSetAt(jsExecState, this.Value, index, v.Value);
        }
        public int GetLength(IntPtr jsExecState)
        {
            return MBApi.jsGetLength(jsExecState, this.Value);
        }
        public void SetLength(IntPtr jsExecState, int length)
        {
            MBApi.jsSetLength(jsExecState, this.Value, length);
        }
        public JsValue Call(IntPtr jsExecState, JsValue function, params JsValue[] args)
        {
            int count = args.Length;
            long[] longArgs = new long[count];
            for (int i = 0; i < count; i++)
            {
                longArgs[i] = args[i].Value;
            }
            return MBApi.jsCall(jsExecState, function, this.Value, longArgs, count);
        }

        #region 属性
        public bool IsNumber
        {
            get { return MBApi.jsIsNumber(Value) != 0; }
        }
        public bool IsString
        {
            get { return MBApi.jsIsString(Value) != 0; }
        }
        public bool IsBoolean
        {
            get { return MBApi.jsIsBoolean(Value) != 0; }
        }
        public bool IsObject
        {
            get { return MBApi.jsIsObject(Value) != 0; }
        }
        public bool IsFunction
        {
            get { return MBApi.jsIsFunction(Value) != 0; }
        }
        public bool IsUndefined
        {
            get { return MBApi.jsIsUndefined(Value) != 0; }
        }
        public bool IsNull
        {
            get { return MBApi.jsIsNull(Value) != 0; }
        }
        public bool IsArray
        {
            get { return MBApi.jsIsArray(Value) != 0; }
        }
        public bool IsTrue
        {
            get { return MBApi.jsIsTrue(Value) != 0; }
        }
        public bool IsFalse
        {
            get { return MBApi.jsIsFalse(Value) != 0; }
        }

        #endregion

        #region 静态方法
        public static void BindFunction(string name, wkeJsNativeFunction fn, IntPtr param, uint argCount)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindFunction(name, fn, param, argCount);
        }
        public static void BindFunction(string name, wkeJsNativeFunction fn, uint argCount)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindFunction(name, fn, IntPtr.Zero, argCount);
        }

        public static void BindGetter(string name, wkeJsNativeFunction fn, IntPtr param)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindGetter(name, fn, param);
        }
        public static void BindGetter(string name, wkeJsNativeFunction fn)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindGetter(name, fn, IntPtr.Zero);
        }

        public static void BindSetter(string name, wkeJsNativeFunction fn, IntPtr param)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindSetter(name, fn, param);
        }
        public static void BindSetter(string name, wkeJsNativeFunction fn)
        {
            if (sm_jsFunctionDictionary.ContainsKey(name))
            {
                sm_jsFunctionDictionary[name] = fn;
            }
            else
            {
                sm_jsFunctionDictionary.Add(name, fn);
            }
            MBApi.wkeJsBindSetter(name, fn, IntPtr.Zero);
        }

        public static int ArgCount(IntPtr jsExecState)
        {
            return MBApi.jsArgCount(jsExecState);
        }

        public static jsType ArgType(IntPtr jsExecState, int argIndex)
        {
            return MBApi.jsArgType(jsExecState, argIndex);
        }

        public static JsValue Arg(IntPtr jsExecState, int argIndex)
        {
            return MBApi.jsArg(jsExecState, argIndex);
        }

        public static JsValue Int32Value(int n)
        {
            return MBApi.jsInt(n);
        }

        public static JsValue FloatValue(float f)
        {
            return MBApi.jsFloat(f);
        }

        public static JsValue DoubleValue(double d)
        {
            return MBApi.jsDouble(d);
        }
        public static JsValue BoolValue(bool b)
        {
            return MBApi.jsBoolean((byte)(b ? 1 : 0));
        }
        public static JsValue UndefinedValue()
        {
            return MBApi.jsUndefined();
        }
        public static JsValue NullValue()
        {
            return MBApi.jsNull();
        }
        public static JsValue TrueValue()
        {
            return MBApi.jsTrue();
        }
        public static JsValue FalseValue()
        {
            return MBApi.jsFalse();
        }
        public static JsValue StringValue(IntPtr jsExecState, string str)
        {
            return MBApi.jsStringW(jsExecState, str);
        }
        public static JsValue EmptyObjectValue(IntPtr jsExecState)
        {
            return MBApi.jsEmptyObject(jsExecState);
        }
        public static JsValue EmptyArrayValue(IntPtr jsExecState)
        {
            return MBApi.jsEmptyArray(jsExecState);
        }
        /// <summary>
        /// 获取一个全局对象(window)的 JsValue 
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <returns></returns>
        public static JsValue GlobalObjectValue(IntPtr jsExecState)
        {
            return MBApi.jsGlobalObject(jsExecState);
        }

        /// <summary>
        /// 获取代表一个对象的JsValue
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <param name="jsObj">继承此类，Overite 方法</param>
        /// <returns></returns>
        public static JsValue ObjectValue(IntPtr jsExecState, JsObject jsObj)
        {
            if (jsObj == null)
                return MBApi.jsUndefined();
            IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(jsData)));
            if (pData == IntPtr.Zero)
                return MBApi.jsUndefined();
            jsData jd = new jsData();
            jd.propertyGet = jsObj.jsGetProperty;
            jd.propertySet = jsObj.jsSetProperty;
            jd.finalize = jsObj.jsFinalize;
            Marshal.StructureToPtr(jd, pData, false);
            return MBApi.jsObject(jsExecState, pData);
        }
        /// <summary>
        /// 获取代表一个方法的JsValue
        /// </summary>
        /// <param name="jsExecState"></param>
        /// <param name="function">继承此类，Overite 方法</param>
        /// <returns></returns>
        public static JsValue FunctionValue(IntPtr jsExecState, JsFunction function)
        {
            if (function == null)
                return MBApi.jsUndefined();
            IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(jsData)));
            if (pData == IntPtr.Zero)
                return MBApi.jsUndefined();
            jsData jd = new jsData();
            jd.callAsFunction = function.jsCallAsFunction;
            jd.finalize = function.jsFinalize;
            Marshal.StructureToPtr(jd, pData, false);
            return MBApi.jsFunction(jsExecState, pData);
        }

        public static IntPtr GetWebView(IntPtr jsExecState)
        {
            return MBApi.jsGetWebView(jsExecState);
        }

        public static JsValue Eval(IntPtr jsExecState, string script)
        {
            return MBApi.jsEvalW(jsExecState, script);
        }

        public static JsValue Eval(IntPtr jsExecState, string script, bool isInClosure)
        {
            return MBApi.jsEvalExW(jsExecState, script, isInClosure);
        }

        public static JsValue CallGlobal(IntPtr jsExecState, JsValue function, params JsValue[] args)
        {
            int count = args.Length;
            long[] longArgs = new long[count];
            for (int i = 0; i < count; i++)
            {
                longArgs[i] = args[i].Value;
            }
            return MBApi.jsCallGlobal(jsExecState, function, longArgs, count);
        }

        public static JsValue GetGlobal(IntPtr jsExecState, string propName)
        {
            return MBApi.jsGetGlobal(jsExecState, propName);
        }

        public static void SetGlobal(IntPtr jsExecState, string propName, JsValue value)
        {
            MBApi.jsSetGlobal(jsExecState, propName, value.Value);
        }

        #endregion


    }

    public class JS
    {
        



    }
}
